<?php

/**
 * Framework_DB_Validator
 *
 *
 * @author Application Support Group
 * @copyright University of Georgia
 * @package BAMF
 * @see Framework_Object
 * @filesource
 */

require_once('Validate.php');

class Framework_DB_Validator extends Framework_Object {


	/**
	 * @todo Implement proper XML test (use loadXML with error suppression? (line 92)
	 * @todo Improve/add restrictions to the date checks? (line 121)
	 */
	public static function validate( $aDaoNode, $mode = DEFAULT_VALIDATION_MODE ) {
		$_output = array() ;
		$_output["errorCount"] = 0;
		$_output["objectError"] = null ;

		$errorMessage = array() ;
		$errorMessage[DB_DATATYPE_INTEGER] = "Value must be an integer.";
		$errorMessage[DB_DATATYPE_FLOAT] = "Value must be a number.";
		$errorMessage[DB_DATATYPE_DATETIME] = "Value must be a valid date.";

		$errorMessage[DB_DATATYPE_TIMESTAMP] = "Value must be a valid timestamp.";

		$errorMessage[DB_DATATYPE_TIME] = "Value must be a valid time.";
		$errorMessage[DB_DATATYPE_STRING_BASIC] = "Value must be a string.";
		$errorMessage[DB_DATATYPE_STRING_EMAIL] = "Value must be a valid email address.";
		$errorMessage[DB_DATATYPE_STRING_PHONE] = "Value must be a valid US phone number.";
		$errorMessage[DB_DATATYPE_STRING_URI ] = "Value must be a valid URI.";
		$errorMessage[DB_DATATYPE_STRING_XML ] = "Value must be a valid XML string.";
		$errorMessage[DB_DATATYPE_CURRENCY] = "Value must be a valid currency amount.";

		if( $aDaoNode instanceof Framework_DB_DaoNode ) {
			if ($mode != 'none') {

				$fields = $aDaoNode->_schema['fields'] ;

				for( $i=0; $i<count( $fields ); $i++ ) {

					$nextField = $fields[$i] ;
					$nextVal = $aDaoNode->{$nextField} ;
					

					// The pkfield for a dao relation is essentially meaningless, but it's not going to be
					// an auto-increment field, so we shouldn't skip over the not-null check.

					if($aDaoNode instanceof Framework_DB_DaoRelation) {
						$pkField = null;
					} else {
						$pkField = $aDaoNode->_schema["db_parameters"]["pkfield"];
					}

					if ( $aDaoNode->_schema['field_values_required'][$nextField] && 
							$aDaoNode->_schema['field_definitions'][$nextField] != DB_DATATYPE_VIRTUAL && 
							$nextField != $pkField) {

						if (in_array( $nextField, array_keys( $aDaoNode->_schema['pk_foreign_keys'] )) || 
								$aDaoNode->_schema['field_definitions'][$nextField] == DB_DATATYPE_KEY 
						   ) {
							if( !(is_numeric( $nextVal ) && intval($nextVal) == $nextVal) || $nextVal < 1) {
								$_output[$nextField] = Framework_ErrorHandler::raiseError( "Value is required.", __METHOD__."::".__LINE__ ) ;
								$_output["errorCount"]++;
							} else {
								$_output[$nextField] = true ;
							}
						} else {
							if( empty( $nextVal ) && !is_numeric($nextVal) ) {
								$_output[$nextField] = Framework_ErrorHandler::raiseError( "Value is required.", __METHOD__."::".__LINE__ ) ;
								$_output["errorCount"]++;
							} else {
								$_output[$nextField] = true ;
							}
						}


					} else {
						$_output[$nextField] = true ;
					}

					if ($mode == 'strict') {
						if ($_output[$nextField]) {
							$fieldDef = $aDaoNode->_schema['field_definitions'][$nextField] ;
							switch ($fieldDef) {

								case DB_DATATYPE_INTEGER:
									if (!empty($nextVal)) $_output[$nextField] = Validate::number($nextVal, array('decimal' => false)) ;
									break ;

								case DB_DATATYPE_FLOAT:
									if( !empty($nextVal )) $_output[$nextField] = Validate::number( $nextVal, array( 'decimal'=>DECIMAL_MARKER )) ;
									break ;

								case DB_DATATYPE_DATETIME:
									if (!empty($nextVal)) {
										if (!strtotime($nextVal)) {
											$_output[$nextField] = false ;
										}
									}
									break ;

								case DB_DATATYPE_TIME:

									if (!empty($nextVal)) $_output[$nextField] = preg_match('/^([01]\d|2[0-3])(:[0-5]\d){0,2}$/', $nextVal);									
									break ;

								case DB_DATATYPE_TIMESTAMP:

									if (!empty($nextVal)) $_output[$nextField] = Validate::number($nextVal, array('decimal' => false, 'min' => 0)) ;									
									break ;

									
								case DB_DATATYPE_STRING_BASIC:
									/* Strings shouldn't need any validation beyond the required check above */
									break ;

								case DB_DATATYPE_STRING_EMAIL:
									if (!empty($nextVal)) $_output[$nextField] = Validate::email($nextVal) ;
									break;

								case DB_DATATYPE_STRING_PHONE:

									//Allow phone numbers with extensions

									$pre_extension = preg_replace('/x\d+$/', '',$nextVal);

									$phone = preg_replace("/\D/", "", $pre_extension);
									if (!empty($nextVal)) {
										$_output[$nextField] = strlen($phone) == 10 ;
									}
									break ;

								case DB_DATATYPE_STRING_URI:
									if (!empty($nextVal)) $_output[$nextField] = Validate::uri($nextVal, array('http', 'https')) ;
									break ;

									/*
									   case DB_DATATYPE_STRING_XML: 
									   $_output[$nextField] = Validate::string($nextVal) ; 
									   break ; 
									 */

								case DB_DATATYPE_CURRENCY:
									if( !empty( $nextVal )) $_output[$nextField] = Validate::number( $nextVal, array('decimal'=>DECIMAL_MARKER, 'dec_prec'=>2, 'min'=>0 )) ;
									break ;

								case DB_DATATYPE_VIRTUAL:
									$_output[$nextField] = true;
									break ;

							}

							if (!$_output[$nextField]) {
								$_output[$nextField] = Framework_ErrorHandler::raiseError( $errorMessage[$fieldDef], __METHOD__."::".__LINE__ ) ;
								$_output["errorCount"]++;
							}
						}
					}



				}// end for

			} else {
				foreach ($aDaoNode->_schema['fields'] as $fieldName) {
					$_output[$fieldName] = true ;
				}
			}


		} else {
			$_output['errorCount']++ ;
			$_output['objectError'] = Framework_ErrorHandler::raiseError( "The supplied argument is not a valid Framework_DB_DaoNode object.", __METHOD__."::".__LINE__ ) ;
		}


		return $_output ;

	}

}

?>
